﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using LitJson;
using System.IO;
using System.Drawing.Drawing2D;
using OCR.SettingsForm;

namespace OCR.Algorithm
{
    class AlgorithmModule_CPU_V2
    {
        //-cpu_ocr
        [DllImport(@"-cpu_ocr.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void CreateInstance();
        [DllImport(@"-cpu_ocr.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr do_ocr(byte[] imageData, int width, int height);
        [DllImport(@"-cpu_ocr.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void DestroyInstance();

        public static List<List<Point>> pointsList = new List<List<Point>>();
        public static List<List<Point>> convertList = new List<List<Point>>();

        public static List<TemplateConfig> currConfigs = new List<TemplateConfig>();

        //new Bitmap(img)  new Bitmap(path)

        //获取图片数据进算法
        public static Image ImageHandleV2(Bitmap bitmap) 
        {
            Console.WriteLine("pixel: " + bitmap.PixelFormat);
            pointsList.Clear();
            // 读取本地图片
            //string imagePath = "G:\\yyx\\3588test\\ocr\\0727\\Image_20240726151820440.bmp"; // 替换图片路径
            //System.Drawing.Bitmap bitmap = new Bitmap(img);

            // 获取图片数据
            Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
            BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);

            int bytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;
            byte[] imageData = new byte[bmpData.Stride * bitmap.Height];

            // 拷贝数据
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, imageData, 0, imageData.Length);
            bitmap.UnlockBits(bmpData);
            //Console.WriteLine(imageData.Length);
            IntPtr resultPtr = do_ocr(imageData, bmpData.Width, bmpData.Height);
            string result = Marshal.PtrToStringAnsi(resultPtr);

            byte[] rebytes = Encoding.Default.GetBytes(result);
            result = Encoding.UTF8.GetString(rebytes).Replace("end", "");

            //byte[] rebytes = Encoding.Default.GetBytes(result);
            //byte[] bytes = Encoding.Convert(Encoding.UTF8, Encoding.Default, rebytes, 0, rebytes.Length);
            //result = Encoding.Default.GetString(bytes, 0, bytes.Length).Replace("end", "");

            Console.WriteLine("OCR Result:\n" + result);

            List<TemplateConfig> configs = new List<TemplateConfig>();
            configs = JsonMapper.ToObject<List<TemplateConfig>>(result);

            for (int i = 0; i < configs.Count; i++)
            {
                Console.WriteLine("算法图片信息" + i + ": " + configs[i].text);
                List<Point> points = new List<Point>();
                for (int j = 0; j < configs[i].box.Count; j++)
                {
                    Point point = new Point(configs[i].box[j][0], configs[i].box[j][1]);
                    points.Add(point);
                }
                pointsList.Add(points);
            }
            currConfigs = configs;


            return bitmap;
        }

        #region 缩放
        //获取图片数据缩放后进算法
        public static Image ImageHandleV2_Zoom(Bitmap bitmap, Rectangle cropArea, int scale = 2)
        {
            pointsList.Clear();

            byte[] imageData = SafeScaleBitmapZoomOut(bitmap, scale);
            IntPtr resultPtr = do_ocr(imageData, bitmap.Width / scale, bitmap.Height / scale);

            string result = Marshal.PtrToStringAnsi(resultPtr);

            byte[] rebytes = Encoding.Default.GetBytes(result);
            result = Encoding.UTF8.GetString(rebytes).Replace("end", "");

            //byte[] rebytes = Encoding.Default.GetBytes(result);
            //byte[] bytes = Encoding.Convert(Encoding.UTF8, Encoding.Default, rebytes, 0, rebytes.Length);
            //result = Encoding.Default.GetString(bytes, 0, bytes.Length).Replace("end", "");

            Console.WriteLine("OCR Result:\n" + result);

            List<TemplateConfig> configs = new List<TemplateConfig>();
            configs = JsonMapper.ToObject<List<TemplateConfig>>(result);

            for (int i = 0; i < configs.Count; i++)
            {
                Console.WriteLine("算法图片信息" + i + ": " + configs[i].text);
                List<Point> points = new List<Point>();
                for (int j = 0; j < configs[i].box.Count; j++)
                {
                    Point point = new Point(configs[i].box[j][0] * scale, configs[i].box[j][1] * scale);
                    //Console.WriteLine(point.X+"  "+point.Y);
                    points.Add(point);
                }
                pointsList.Add(points);
            }
            currConfigs = configs;
            convertList = ConvertPointList(pointsList, cropArea);


            return bitmap;
        }

        //new Rectangle(x: 218, y: 530, width: 748, height: 310)

        //获取图片数据缩放
        private static byte[] SafeScaleBitmapZoomOut(Bitmap srcBmp, int scale)
        {

            // 1. 加载源图像
            //Bitmap srcBmp = new Bitmap(path);

            int channels = Image.GetPixelFormatSize(srcBmp.PixelFormat) / 8;
            Console.WriteLine(channels);
            // 2. 创建目标图像（示例缩放为50%）
            int newWidth = srcBmp.Width / scale;
            int newHeight = srcBmp.Height / scale;
            Bitmap dstBmp = new Bitmap(newWidth, newHeight, srcBmp.PixelFormat);

            // 3. 获取像素数据
            var srcData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height),
                ImageLockMode.ReadOnly, srcBmp.PixelFormat);
            var dstData = dstBmp.LockBits(new Rectangle(0, 0, newWidth, newHeight),
                ImageLockMode.WriteOnly, dstBmp.PixelFormat);

            // 4. 创建托管缓冲区
            byte[] srcBuffer = new byte[srcData.Stride * srcBmp.Height];
            byte[] dstBuffer = new byte[dstData.Stride * newHeight];
            Marshal.Copy(srcData.Scan0, srcBuffer, 0, srcBuffer.Length);

            // 5. 执行安全缩放（双线性插值）
            SafeBilinearScale(srcBuffer, dstBuffer,
                srcBmp.Width, srcBmp.Height,
                newWidth, newHeight,
                channels);

            // 6. 写回并显示
            //Marshal.Copy(dstBuffer, 0, dstData.Scan0, dstBuffer.Length);
            srcBmp.UnlockBits(srcData);
            dstBmp.UnlockBits(dstData);

            return dstBuffer;
            //picResult.Image = dstBmp;
        }
        //图片数据缩放
        private static void SafeBilinearScale(byte[] src, byte[] dst,
    int srcWidth, int srcHeight,
    int dstWidth, int dstHeight,
    int channels)
        {
            float xRatio = (float)srcWidth / dstWidth;
            float yRatio = (float)srcHeight / dstHeight;
            int srcStride = srcWidth * channels;

            for (int y = 0; y < dstHeight; y++)
            {
                float srcY = y * yRatio;
                int y0 = (int)srcY;
                int y1 = Math.Min(y0 + 1, srcHeight - 1);
                float wy = srcY - y0;

                for (int x = 0; x < dstWidth; x++)
                {
                    float srcX = x * xRatio;
                    int x0 = (int)srcX;
                    int x1 = Math.Min(x0 + 1, srcWidth - 1);
                    float wx = srcX - x0;

                    // 获取四个相邻像素的索引
                    int i00 = (y0 * srcWidth + x0) * channels;
                    int i01 = (y0 * srcWidth + x1) * channels;
                    int i10 = (y1 * srcWidth + x0) * channels;
                    int i11 = (y1 * srcWidth + x1) * channels;

                    // 计算目标像素索引
                    int dstIndex = (y * dstWidth + x) * channels;

                    for (int c = 0; c < channels; c++)
                    {
                        // 双线性插值计算
                        float v00 = src[i00 + c];
                        float v01 = src[i01 + c];
                        float v10 = src[i10 + c];
                        float v11 = src[i11 + c];

                        float top = v00 * (1 - wx) + v01 * wx;
                        float bottom = v10 * (1 - wx) + v11 * wx;
                        dst[dstIndex + c] = (byte)(top * (1 - wy) + bottom * wy);
                    }
                }
            }
        }
        /// <summary>
        /// 点位数组List全部转换
        /// </summary>
        /// <param name="pointList">点位数组List</param>
        /// <param name="cropArea">框选区域</param>
        /// <returns></returns>
        public static List<List<Point>> ConvertPointList(List<List<Point>> pointList, Rectangle cropArea)
        {
            List<List<Point>> tempList = new List<List<Point>>();
            for (int i = 0; i < pointList.Count; i++)
            {
                tempList.Add(ConvertPointsToOriginal(pointList[i].ToArray(), cropArea).ToList());
            }

            return tempList;
        }
        //点位数组转换为原图点位
        private static Point[] ConvertPointsToOriginal(Point[] croppedPoints, Rectangle cropArea)
        {
            Point[] points = croppedPoints.Select(p => new Point(
                  p.X + cropArea.X,
                  p.Y + cropArea.Y
              )).ToArray();
            foreach (var item in points)
            {
                //Console.WriteLine("Convert: "+"x;"+item.X+"   "+"y:" + item.Y);
            }
            return points;

        }

        //裁剪原图，截取框选区域
        public static Image CropImage(Bitmap originalImage, Rectangle cropArea, string outputPath = "", string outputRectPath = "")
        {
            // 加载原始图片
            using (originalImage)
            {
                // 检查裁剪区域是否有效
                if (cropArea.X < 0 || cropArea.Y < 0 ||
                    cropArea.Width <= 0 || cropArea.Height <= 0 ||
                    cropArea.Right > originalImage.Width ||
                    cropArea.Bottom > originalImage.Height)
                {
                    throw new ArgumentException("Invalid crop area");
                }

                // 创建目标位图
                using (var croppedImage = new Bitmap(cropArea.Width, cropArea.Height))
                {
                    // 创建绘图对象
                    using (var graphics = Graphics.FromImage(croppedImage))
                    {
                        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        graphics.SmoothingMode = SmoothingMode.HighQuality;
                        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        graphics.CompositingQuality = CompositingQuality.HighQuality;
                        // 绘制裁剪区域
                        graphics.DrawImage(
                            originalImage,
                            new Rectangle(0, 0, croppedImage.Width, croppedImage.Height),
                            cropArea,
                            GraphicsUnit.Pixel
                        );
                    }
                    Bitmap bitmap = ConvertTo8bpp(croppedImage);

                    ImageHandleV2_Zoom(bitmap, cropArea, 2);

                    if (outputPath != "")
                    {
                        bitmap.Save(outputPath, originalImage.RawFormat);
                    }
                    //bitmap.Save(outputPath, originalImage.RawFormat);
                    // 保存图片
                    //croppedImage.Save(outputPath, originalImage.RawFormat);

                    Image image = RectPoints(originalImage, convertList);
                    if (outputRectPath != "")
                    {
                        image.Save(outputRectPath, originalImage.RawFormat);
                    }


                    return image;
                }
            }
        }
        /// <summary>
        /// 画框
        /// </summary>
        /// <param name="bitmap">获取图片数据</param>
        /// <param name="pointsList">点位数组List</param>
        /// <returns></returns>
        public static Image RectPoints(Bitmap bitmap, List<List<Point>> pointsList)
        {
            //Bitmap bitmap = new Bitmap(bitmapInput);
            Bitmap convertedImage = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb);

            using (Graphics g = Graphics.FromImage(convertedImage))
            {
                g.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height);
            }

            Graphics graphics1 = Graphics.FromImage(convertedImage);

            Pen pen = new Pen(Color.Green, 5);

            foreach (var item in pointsList)
            {
                graphics1.DrawLines(pen, item.ToArray());
                graphics1.DrawLine(pen, item.ToArray()[0], item.ToArray()[3]);
            }

            graphics1.Dispose();
            return convertedImage;
        }
        //转为8位像素  （使用Graphics重新画图像（包括裁剪）时，不能创建8位像素的对象，画完图后转为8位像素）
        private static Bitmap ConvertTo8bpp(Bitmap original)
        {
            // 创建目标 8bpp 位图
            Bitmap target = new Bitmap(
                original.Width,
                original.Height,
                PixelFormat.Format8bppIndexed
            );

            // 设置灰度调色板（典型 8bpp 调色板）
            ColorPalette palette = target.Palette;
            for (int i = 0; i < 256; i++)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            target.Palette = palette;

            // 锁定位图数据
            BitmapData originalData = original.LockBits(
                new Rectangle(0, 0, original.Width, original.Height),
                ImageLockMode.ReadOnly,
                original.PixelFormat
            );

            BitmapData targetData = target.LockBits(
                new Rectangle(0, 0, target.Width, target.Height),
                ImageLockMode.WriteOnly,
                target.PixelFormat
            );

            try
            {
                // 手动转换像素（简单亮度公式）
                unsafe
                {
                    byte* targetPtr = (byte*)targetData.Scan0;
                    int* originalPtr = (int*)originalData.Scan0;

                    for (int i = 0; i < original.Height; i++)
                    {
                        for (int j = 0; j < original.Width; j++)
                        {
                            int pixel = originalPtr[j];
                            // 亮度公式：0.299*R + 0.587*G + 0.114*B
                            byte brightness = (byte)(
                                (pixel & 0xFF) * 0.114 +         // B
                                ((pixel >> 8) & 0xFF) * 0.587 +  // G
                                ((pixel >> 16) & 0xFF) * 0.299   // R
                            );
                            targetPtr[j] = brightness;
                        }
                        targetPtr += targetData.Stride;
                        originalPtr += originalData.Stride / 4;
                    }
                }
            }
            finally
            {
                original.UnlockBits(originalData);
                target.UnlockBits(targetData);
            }

            return target;
        }
        #endregion

    }
}
